package com.niuke;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Scanner;

/**
 * 51. 相同数字组成图形的周长
 * https://zhuanlan.zhihu.com/p/647319337
 */
public class NiukeMoni51 {

    public static void main(String[] args) {

        Scanner scanner = new Scanner(System.in);
        int n = Integer.parseInt(scanner.nextLine()); // 表示后面输入n行

        List<Integer> number = new ArrayList<>();  // 存储填充的数字
        List<List<int[]>> positions = new ArrayList<>(); // 存储填充数字的下标
        for (int i = 0; i < n; i++) {
            String[] line = scanner.nextLine().split(" ");
            number.add(Integer.parseInt(line[0]));
            List<int[]> item = new ArrayList<>();
            for (int j = 0; j < (line.length - 1) / 2; j++) {
                int[] p = new int[2];
                p[0] = Integer.parseInt(line[2 * j + 1]);
                p[1] = Integer.parseInt(line[2 * j + 2]);
                item.add(p);
            }

            item.sort(new Comparator<int[]>() {
                @Override
                public int compare(int[] ints, int[] t1) {
                    if (ints[0] == t1[0]) {
                        return ints[1] - t1[1];
                    }
                    return ints[0] - t1[0];
                }
            });

            positions.add(item);
        }


        int[] result = new int[n];

        for (int i = 0; i < positions.size(); i++) {
            int c = 0; // 周长

            List<int[]> positionList = positions.get(i);
            int preRow = -1;
            int preStart = -1;
            int preEnd = -1;
            int currStart = -1;
            int currEnd = -1;

            for (int j = 0; j < positionList.size(); j++) {
                int[] p = positionList.get(j);
                int currRow = p[0];
                int currCol = p[1];
                if (preRow == -1 || preRow != currRow) { // 换行了
//                    System.out.println(preRow + ", " + currEnd + ", " + currStart + ", " + preEnd + ", " + preStart);
                    if (preRow != -1) {
                        c += 4 * (currEnd - currStart + 1) - 2 * (currEnd - currStart);

                        if (preStart != -1 && preEnd != -1) {
                            if (preStart > currEnd || preEnd < currStart) { // 无交集，从题意看肯定不会发生

                            } else {
                                int min = Math.max(preStart, currStart);
                                int max = Math.min(preEnd, currEnd);
                                c -= 2 * (max - min + 1);
                            }
                        }

                        preStart = currStart;
                        preEnd = currEnd;
                    }
                    currStart = currCol; // 改当前行的起始列
                    preRow = currRow;
                }

                currEnd = currCol; // 不断改当前行的终止列

                if (j == positionList.size() - 1) { // 最后的位置也要结算一次周长
                    c += 4 * (currEnd - currStart + 1) - 2 * (currEnd - currStart);

                    if (preStart != -1 && preEnd != -1) {
                        if (preStart > currEnd || preEnd < currStart) { // 无交集，从题意看肯定不会发生

                        } else {
                            int min = Math.max(preStart, currStart);
                            int max = Math.min(preEnd, currEnd);
                            c -= 2 * (max - min + 1);
                        }
                    }
                }
            }


            result[i] = c;
        }

        System.out.println(Arrays.toString(result));

    }

}
